package com.magnate.software.jdk;

import com.magnate.software.jdk.domain.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * jdk1.8 Lambda Stream demo
 *
 * @author WangYang
 * @version 1.0
 * @datetime 2017/1/10 15:30
 */
public class LambdaStream {

    public static List<User> users = new ArrayList();

    static {
        users.add(new User("x", "bj", 28));
        users.add(new User("y", "bj", 19));
        users.add(new User("z", "wh", 33));
        users.add(new User("j", "cq", 58));
    }

    public static void main(String[] args) {
        filter();
        collect();
        map();
        flatMap();
        minMax();
        reduce();
        demo();
    }

    /**
     * 遍历数据并检查其中的元素，排除所有与断言不匹配的元素
     */
    public static void filter() {
        // 找出来自bj的用户总数
        long count = users.stream()
                .filter(user -> user.getCity().equals("bj"))
                .count();
        System.out.println(count);

        long count1 = users.stream()
                .filter(user -> {
                    System.out.print(user.getName());
                    return user.getCity().equals("bj");
                }).count();
        System.out.println(count1);
    }

    /**
     * 由Stream里的值生成一个列表，及早求值操作
     */
    public static void collect() {
        List<User> temp = users.stream()
                .filter(user -> user.getCity().equals("bj"))
                .collect(Collectors.toList());
        temp.forEach(user -> System.out.print(user.getName()));
        System.out.println();
    }

    /**
     * 如果有一个函数可以将一种类型的值转换成另外一种类型，就可以使用map函数，将一个流中的值转换成为一个新的流
     */
    public static void map() {
        List<String> stringList = Stream.of("a", "b", "c")
                .map(string -> string.toUpperCase())
                .collect(Collectors.toList());
        stringList.forEach(string -> System.out.print(string));
        System.out.println();
    }

    /**
     * flatMap函数可用于Stream替换值，然后将多个Stream连接成为一个Stream
     */
    public static void flatMap() {
        List<Integer> integers = Stream.of(Stream.of(1, 2), Stream.of(3, 4))
                .flatMap(stream -> stream)
                .collect(Collectors.toList());
        integers.forEach(integer -> System.out.print(integer));
        System.out.println();
    }

    /**
     * max和min函数，分别是取最大值和最小值
     */
    public static void minMax() {
        User maxUser = users.stream().max(Comparator.comparing(user -> user.getAge())).get();
        System.out.println(maxUser.getName() + " " + maxUser.getAge());
        User minUser = users.stream().min(Comparator.comparing(user -> user.getAge())).get();
        System.out.println(minUser.getName() + " " + minUser.getAge());
    }

    /**
     * 通过一个二进制操作将流中的元素合并到一起
     */
    public static void reduce() {
        Integer integer = Stream.of(1, 2, 3, 4)
                .reduce(0, (acc, element) -> acc + element);
        System.out.println(integer);
    }

    /**
     * 综合实例
     * 找出年龄大于20的所有用户，并统计用户来自的城市，并去重，并按字母排序
     */
    public static void demo() {
        List<String> cityList = users.stream()
                .filter(user -> user.getAge() > 20)
                .map(user -> user.getCity())
                .distinct()
                .sorted(Comparator.comparing(string -> string))
                .collect(Collectors.toList());
        cityList.forEach(string -> System.out.println(string));
    }
}
